﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace PSZT
{
    public class Predykat
    {
        public int liczbaArgumentow {get; set; }
        public string nazwa { get; set; }
        public List<string> argumenty = new List<string>();

        public Predykat()
        {
            nazwa = "";
            liczbaArgumentow = 0;
        }

        public static bool czyZmienna(string arg)
        {
            Regex regex = new Regex(@"[A-Z]+");
            if (!regex.IsMatch(arg))
            {
                return true;
            }
            return false;
        }

        public Predykat(string nazwa, int liczbaArgumentow)
        {
            this.nazwa = nazwa;
            this.liczbaArgumentow = liczbaArgumentow;
        }


        public static bool czyStala(string arg)
        {
            return !czyZmienna(arg);
        }

        public bool czyPrawidlowy(Predykat pr)
        {
            return pr.liczbaArgumentow == pr.argumenty.Count;
        }

        override public string ToString()
        {
            string ret;
            ret = nazwa + "(";
            foreach (string s in argumenty)
            {
                ret += s;
                ret += ",";
            }
            ret = ret.Remove(ret.Count() - 1);
            ret += ")";
            return ret;
        }

        public bool jestUnifikowalnyZ(Predykat pred)
        {
            if (this.nazwa != pred.nazwa || this.argumenty.Count != pred.argumenty.Count)
            {
                return false;
            }
            for (int i = 0; i < this.argumenty.Count; ++i)
            {
                if (Predykat.czyStala(this.argumenty[i]) && Predykat.czyStala(pred.argumenty[i]) && this.argumenty[i] != pred.argumenty[i])
                {
                    return false;
                }
            }
            return true;
        }

        public Podstawienie znajdzPodstawienia(Predykat literal)
        {
            Podstawienie result = new Podstawienie();
            for (int i = 0; i < this.argumenty.Count; ++i)
            {
                if (result.podstawienia.ContainsKey(this.argumenty[i]) && result.podstawienia[this.argumenty[i]] != literal.argumenty[i])
                {
                    return null;
                }
                else
                {
                    result.podstawienia.Add(this.argumenty[i], literal.argumenty[i]);
                }
            }

            return result;
        }

        public Predykat podstaw(int[] ustawieniaStosu, List<Podstawienie>[] sensownePodstawienia)
        {
            Predykat result = new Predykat(this.nazwa, this.liczbaArgumentow) { argumenty = new List<string>() };
            Podstawienie uzywanePodstawienia = new Podstawienie();

            for (int i = 0; i < ustawieniaStosu.Length; ++i)
            {
                foreach (Podstawienie p in sensownePodstawienia[i])
                {
                    foreach (KeyValuePair<string, string> pair in p.podstawienia)
                    {
                        if (!uzywanePodstawienia.podstawienia.Keys.Contains(pair.Key))
                        {
                            uzywanePodstawienia.podstawienia.Add(pair.Key, pair.Value);
                        }
                    }
                }
            }


            foreach (string arg in argumenty)
            {
                if (Predykat.czyStala(arg))
                {
                    result.argumenty.Add(arg);
                }
                else
                {
                    try
                    {
                        result.argumenty.Add(uzywanePodstawienia.podstawienia[arg]);
                    }
                    catch (KeyNotFoundException)
                    {
                        return null;
                    }
                }
            }

            return result;
        }

        public override bool Equals(object obj)
        {
            if (!this.GetType().Equals(obj.GetType())) {
                return false;
            }

            Predykat p = obj as Predykat;
            if (this.liczbaArgumentow == p.liczbaArgumentow && this.nazwa.Equals(p.nazwa) && this.argumenty.SequenceEqual(p.argumenty)) {
                return true;
            }
            return false;
        }
    }
}
